﻿using UnityEngine;
using System.Collections;
using System.Threading;

namespace GameBasic
{
    /// <summary>
    /// 
    /// </summary>
    public static class ThreadIds
    {
        private static int MainThread;
        private static int[] Ids;
        private static object DataLock = new object();

        static void Init()
        {
            MainThread = Thread.CurrentThread.ManagedThreadId;  
            Ids = null;
        }

        public static void Clear()
        {
            MainThread = 0;
            Ids = null;
            DataLock = null;
        }

        /// <summary>
        /// Is main thread?
        /// </summary>
        /// <returns></returns>
        public static bool IsMain()
        {
            return MainThread == Thread.CurrentThread.ManagedThreadId;
        }

        /// <summary>
        /// Get current thread index
        /// </summary>
        /// <returns></returns>
        public static int GetIndex()
        {
            if (Ids == null)
                Init();

            int current = Thread.CurrentThread.ManagedThreadId;
            if (current == MainThread)
                return 0;

            int result = 0;
            lock (Ids)
            {
                // search
                if (Ids != null)
                {
                    for (int i = 0, length = Ids.Length; i < length; i++)
                    {
                        if (Ids[i] == current)
                        {
                            result = i;
                            break;
                        }
                    }
                }

                // not found
                if (result == 0)
                {
                    // Add to last
                    ArrayTools.Add(ref Ids, current);
                    result = Ids.Length;
                }
            }

            return result;
        }

        /// <summary>
        /// Get 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mainThreadData"></param>
        /// <param name="datas"></param>
        /// <param name="locker"></param>
        /// <returns></returns>
        public static ref T Get<T>(ref T mainThreadData, ref ThreadData<T>[] datas)
        {
            if (Ids == null)
                Init();

            int current = Thread.CurrentThread.ManagedThreadId;
            if (current == MainThread)
                return ref mainThreadData;

            int index = 0;
            var cache = datas;
            // search
            if (cache != null)
            {
                for (int i = 0, length = cache.Length; i < length; i++)
                {
                    if (cache[i].thread == current)
                    {
                        index = i;
                        break;
                    }
                }
            }

            // not found, create new
            if (index == 0)
            {
                var id = new ThreadData<T>
                {
                    thread = current
                };

                // add to last
                lock (DataLock)
                {
                    ArrayTools.Add(ref datas, id);
                    index = datas.Length;
                }
            }

            return ref datas[index].data;
        }
    }

    public struct ThreadData<T>
    {
        public int thread;
        public T data;
    }
}